/* Thread management routine header.
 * Copyright (C) 2012 Tsihang
 *
 * This file is part of GNU Zebra.
 *
 * GNU Zebra is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * GNU Zebra is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.  
 */

#ifndef _THREAD_H_
#define _THREAD_H_


#ifdef __cplusplus
extern "C"{
#endif
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <time.h> 
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
//#include <net/uio.h>
#include <stdarg.h>
#include <assert.h>

#include <netinet/in.h>
/*#endif*/ /* HAVE_NETINET_IN_H */
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <net/route.h>


#ifdef HAVE_RUSAGE
#define RUSAGE_T        		struct rusage
#define RPC_GETRUSAGE(X)    	getrusage (RUSAGE_SELF, X);
#else
#define RUSAGE_T        		struct timeval
#define RPC_GETRUSAGE(X)    	rpc_gettimeofday (X, NULL);
#endif /* HAVE_RUSAGE */

/* Linked list of thread. */
struct thread_list_rpc
{
  	struct thread_rpc *head;
  	struct thread_rpc *tail;
 	 int count;
};

/* Master of the theads. */
struct thread_master_rpc
{
  	struct thread_list_rpc read;
  	struct thread_list_rpc write;
  	struct thread_list_rpc timer;
  	struct thread_list_rpc event;
  	struct thread_list_rpc ready;
  	struct thread_list_rpc unuse;
 	fd_set readfd;
  	fd_set writefd;
  	fd_set exceptfd;
  	unsigned long alloc;
};

/* Thread itself. */
struct thread_rpc
{
  	unsigned char type;		/* thread type */
  	struct thread_rpc *next;		/* next pointer of the thread */
  	struct thread_rpc *prev;		/* previous pointer of the thread */
  	struct thread_master_rpc *master;	/* pointer to the struct thread_master. */
  	int (*func) (int libIndex, struct thread_rpc *); /* event function */
  	void *arg;			/* event argument */
  	union {
    			int val;			/* second argument of the event. */
    			int fd;			/* file descriptor in case of read/write. */
    			struct timeval sands;	/* rest of time sands value. */
  	} u;
  	RUSAGE_T ru;			/* Indepth usage info.  */
};

/* Thread types. */
#define RPC_THREAD_READ           	0
#define RPC_THREAD_WRITE          	1
#define RPC_THREAD_TIMER          	2
#define RPC_THREAD_EVENT          	3
#define RPC_THREAD_READY          	4
#define RPC_THREAD_UNUSED        	5

/* Thread yield time.  */
#define RPC_THREAD_YIELD_TIME_SLOT     100 * 1000L /* 100ms */

/* Macros. */
#define RPC_THREAD_ARG(X) ((X)->arg)
#define RPC_THREAD_FD(X)  ((X)->u.fd)
#define RPC_THREAD_VAL(X) ((X)->u.val)

#define RPC_THREAD_READ_ON(master,thread,func,arg,sock) \
  do { \
    if (! thread) \
      thread = rpc_thread_add_read (libIndex, master, func, arg, sock); \
  } while (0)

#define RPC_THREAD_WRITE_ON(master,thread,func,arg,sock) \
  do { \
    if (! thread) \
      thread = rpc_thread_add_write (libIndex, master, func, arg, sock); \
  } while (0)

#define RPC_THREAD_TIMER_ON(master,thread,func,arg,time) \
  do { \
    if (! thread) \
      thread = rpc_thread_add_timer (libIndex, master, func, arg, time); \
  } while (0)

#define RPC_THREAD_OFF(thread) \
  do { \
    if (thread) \
      { \
        rpc_thread_cancel (libIndex, thread); \
        thread = NULL; \
      } \
  } while (0)

#define RPC_THREAD_READ_OFF(thread)  RPC_THREAD_OFF(thread)
#define RPC_THREAD_WRITE_OFF(thread)  RPC_THREAD_OFF(thread)
#define RPC_THREAD_TIMER_OFF(thread)  RPC_THREAD_OFF(thread)

/* Prototypes. */
struct thread_master_rpc *rpc_thread_master_create (int);
struct thread_rpc *rpc_thread_add_read (int, struct thread_master_rpc *, 
				int (*)(int, struct thread_rpc *), void *, int);
struct thread_rpc *rpc_thread_add_write (int, struct thread_master_rpc *,
				 int (*)(int, struct thread_rpc *), void *, int);
struct thread_rpc *rpc_thread_add_timer (int, struct thread_master_rpc *,
				 int (*)(int, struct thread_rpc *), void *, long);
struct thread_rpc *rpc_thread_add_event (int, struct thread_master_rpc *,
				 int (*)(int, struct thread_rpc *), void *, int );
void rpc_thread_cancel (int, struct thread_rpc *);
void rpc_thread_cancel_event (int, struct thread_master_rpc *, void *);

struct thread_rpc *rpc_thread_fetch (int, struct thread_master_rpc *, struct thread_rpc *);
struct thread_rpc *rpc_thread_execute (int, struct thread_master_rpc *,
			       int (*)(int, struct thread_rpc *), void *, int);
void rpc_thread_call (int libIndex, struct thread_rpc *);
unsigned long rpc_thread_timer_remain_second (int, struct thread_rpc *);

extern int rpc_gettimeofday(struct timeval  *tv, void *tz);
#ifdef __cplusplus
}
#endif
#endif 

